package net;

import java.io.File;
import java.util.Collection;
import java.util.LinkedList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import message.Message;
import message.Packet;
import message.handler.PersistentMessageHandler;

public class VirtualQueue {

	private static VirtualQueue vs = null;
	private LinkedList<Packet> highPriorityMessagesStack;
	private LinkedList<Packet> lowPriorityMessageStack;
	private LinkedList<String> storedMessagesStack;

	private VirtualQueue() {
		this.highPriorityMessagesStack = new LinkedList<>();
		this.lowPriorityMessageStack = new LinkedList<>();
		this.storedMessagesStack = new LinkedList<>();
	}

	public void pushHighPriorityMessage(Packet p) {
		synchronized (this) {
			this.highPriorityMessagesStack.addLast(p);
			this.notifyAll();
		}
	}

	public void pushLowPriorityMessage(Packet p) {
		synchronized (this) {
			this.lowPriorityMessageStack.addLast(p);
			this.notifyAll();
		}
	}

	public Packet popMessage() {
		synchronized (this) {
			if (this.size() == 0) {
				try {
					this.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			if (highPriorityMessagesStack.size() > 0) {
				return this.highPriorityMessagesStack.remove(0);
			} else {
				return this.lowPriorityMessageStack.remove(0);
			}
		}
	}

	private int size() {
		return highPriorityMessagesStack.size()
					+ lowPriorityMessageStack.size();
	}

	public Collection<String> removeOutgoingMessagesTo(String username) {
		synchronized (this) {
			LinkedList<String> outcomingMessages = new LinkedList<>();
			int i = 0;
			for (Packet packet : this.highPriorityMessagesStack) {
				if (packet.isMessage()
						&& ((Message) packet).getReceiver().equals(username)) {
					outcomingMessages.add(packet.toXML());
					this.highPriorityMessagesStack.remove(i);
				}
				i++;
			}

			i = 0;
			for (Packet packet : this.lowPriorityMessageStack) {
				if (packet.isMessage()
						&& ((Message) packet).getReceiver().equals(username)) {
					outcomingMessages.add(packet.toXML());
					this.lowPriorityMessageStack.remove(i);
				}
				i++;
			}
			return outcomingMessages;
		}
	}

	public void storeMessage(String filename) {
		synchronized (this) {
			this.storedMessagesStack.add(filename);
		}
	}

	public Collection<String> popStoredMessagesTo(String username) {
		synchronized (this) {
			Collection<String> fileNames = new LinkedList<>();
			Pattern p = Pattern.compile("(" + username + ")#.+");
			
			File cloudFolder = new File(PersistentMessageHandler.folder);
			cloudFolder.mkdir();
			
			for (String fileName : this.storedMessagesStack) {
				Matcher m = p.matcher(fileName);
				if (m.matches()) {
					fileNames.add(fileName);
					this.storedMessagesStack.remove(fileName);
				}
			}

			return fileNames;
		}
	}

	public synchronized static void _clearVirtualQueue(){
		vs = null;
	}

	public int _persistentFileSize(){
		synchronized (this) {
			return this.storedMessagesStack.size();
		}
	}
	
	public int _highPriorityQueueSize(){
		synchronized (this) {
			return this.highPriorityMessagesStack.size();
		}
	}
	
	public synchronized static VirtualQueue obtainVirtualQueue() {
		if (vs == null)
			vs = new VirtualQueue();
		return vs;
	}
}
